/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.debugger.debug;
import java.beans.*;
import java.util.*;
import javax.swing.SwingUtilities;
import sun.tools.debug.RemoteThread;
import sun.tools.debug.RemoteStackFrame;
import sun.tools.debug.RemoteStackVariable;
import org.openide.debugger.DebuggerException;
import org.openide.text.Line;
import org.netbeans.modules.debugger.support.AbstractDebugger;
import org.netbeans.modules.debugger.support.AbstractThread;
import org.netbeans.modules.debugger.support.CallStackFrame;
import org.netbeans.modules.debugger.support.AbstractVariable;
import org.netbeans.modules.debugger.support.util.Protector;
import org.netbeans.modules.debugger.support.util.Utils;
public class ToolsThread extends AbstractThread {
// variables .......................................................................
/** This debugger. */
private ToolsDebugger debugger;
/** Representing thread. */
private RemoteThread thread;
/** Cache for old locales value. */
private HashMap oldLocales = new HashMap ();
/** Cache for old call stack. */
private ToolsCallStackFrame [] oldCallStack = new ToolsCallStackFrame [0];
// last stack depth
transient private int lastStackDepth = 0;
// last action performed on the thread
transient private int lastAction = AbstractDebugger.ACTION_START;
// init ............................................................................
ToolsThread (
ToolsDebugger debugger,
ToolsThreadGroup parentThreadGroup,
RemoteThread thread
) {
super (debugger, parentThreadGroup);
this.debugger = debugger;
this.thread = thread;
if ( (parentThreadGroup != null) &&
(debugger.lastCurrentThread != null) &&
thread.equals (debugger.lastCurrentThread)
) {
setCurrent (true);
debugger.lastCurrentThread = null;
}
}
// implementation of AbstractThread .....................................................
/**
* Getter for the name of thread property.
*
* @throw DebuggerException if some problem occurs.
* @return name of thread.
*/
public String getName () throws DebuggerException {
if (debugger.synchronizer == null) return "Thread"; // NOI18N
try {
return (String) new Protector ("ToolsThread.getName") { // NOI18N
public Object protect () throws Exception {
return thread.getName ();
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
throw new DebuggerException (e);
}
}
/**
* If this thread is suspended returns line number where this thread is stopped.
*
* @throw DebuggerException if some problem occurs.
* @return line number where this thread is stopped.
*/
public int getLineNumber () throws DebuggerException {
if (debugger.synchronizer == null) return -1;
try {
return ((Integer) new Protector ("ToolsThread.getLineNumber") { // NOI18N
public Object protect () throws Exception {
return new Integer (thread.getCurrentFrame ().getLineNumber ());
}
}.throwAndWait (debugger.synchronizer, debugger.killer)).intValue ();
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
return -1;
}
}
/**
* Returns string representation of the current state of this thread (depends on
* debugger implementation).
*
* @throw DebuggerException if some problem occurs.
* @return string representation of the current state of this thread.
*/
public String getState () throws DebuggerException {
if (debugger.synchronizer == null) return ""; // NOI18N
try {
return (String) new Protector ("ToolsThread.getState") { // NOI18N
public Object protect () throws Exception {
return thread.getStatus ();
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
throw new DebuggerException (e);
}
}
/**
* If this thread is suspended returns class name where this thread is stopped.
*
* @throw DebuggerException if some problem occurs.
* @return class name where this thread is stopped.
*/
public String getClassName () throws DebuggerException {
if (debugger.synchronizer == null) return ""; // NOI18N
try {
return (String) new Protector ("ToolsThread.getClassName") { // NOI18N
public Object protect () throws Exception {
return thread.getCurrentFrame ().getRemoteClass ().getName ();
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
return ""; // NOI18N
}
}
/**
* If this thread is suspended returns method name where this thread is stopped.
*
* @throw DebuggerException if some problem occurs.
* @return method name where this thread is stopped.
*/
public String getMethod () throws DebuggerException {
if (debugger.synchronizer == null) return ""; // NOI18N
try {
return (String) new Protector ("ToolsThread.getClassName") { // NOI18N
public Object protect () throws Exception {
return thread.getCurrentFrame ().getMethodName ();
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
return ""; // NOI18N
}
}
/**
* Returns current stack depth.
*
* @throw DebuggerException if some problem occurs.
* @return current stack depth.
*/
public int getStackDepth () throws DebuggerException {
if (debugger.synchronizer == null) return -1;
try {
return ((Integer) new Protector ("ToolsThread.getStackDepth") { // NOI18N
public Object protect () throws Exception {
return new Integer (thread.dumpStack ().length);
}
}.throwAndWait (debugger.synchronizer, debugger.killer)).intValue ();
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
return -1;
}
}
/**
* Returns true if this thread is suspended.
*
* @throw DebuggerException if some problem occurs.
* @return true if this thread is suspended.
*/
public boolean isSuspended () throws DebuggerException {
if (debugger.synchronizer == null) return false;
try {
return ((Boolean) new Protector ("ToolsThread.isSuspended") { // NOI18N
public Object protect () throws Exception {
return new Boolean (thread.isSuspended ());
}
}.throwAndWait (debugger.synchronizer, debugger.killer)).booleanValue ();
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
throw new DebuggerException (e);
}
}
/**
* Setter method for the suspend property.
*
* @throw DebuggerException if some problem occurs.
* @param suspend true if this thread might be suspend.
*/
public void setSuspended (final boolean suspend) throws DebuggerException {
if (debugger.synchronizer == null) return;
final boolean o = isSuspendedIn ();
if (o == suspend) return;
try {
if (suspend)
suspendIn ();
else {
resumeIn ();
contIn ();
}
if (o != isSuspendedIn ())
super.setSuspended (suspend);
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
throw new DebuggerException (e);
}
}
/**
* Stops this thread.
*
* @throw DebuggerException if some problem occurs.
*/
public void stop () throws DebuggerException {
if (debugger.synchronizer == null) return;
try {
new Protector ("ToolsThread.setSuspend") { // NOI18N
public Object protect () throws Exception {
thread.stop ();
return null;
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
throw new DebuggerException (e);
}
}
/**
* If this thread is suspended returns current call stack.
*
* @return current call stack.
*/
public CallStackFrame[] getCallStack () {
if (debugger.synchronizer == null) return new ToolsCallStackFrame [0];
RemoteStackFrame[] rStack = null;
try {
if (!isSuspended ()) return new ToolsCallStackFrame [0];
rStack = (RemoteStackFrame[]) new Protector ("ToolsThread.getCallStack") { // NOI18N
public Object protect () throws Exception {
return thread.dumpStack ();
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
return new ToolsCallStackFrame [0];
}
int i, k = Math.min (rStack.length, oldCallStack.length);
ToolsCallStackFrame[] theStack = new ToolsCallStackFrame [rStack.length];
for (i = 0; i < k; i++) {
theStack [theStack.length-i-1] = new ToolsCallStackFrame (debugger, rStack [theStack.length-i-1]);
theStack [theStack.length-i-1].oldLocales = oldCallStack [oldCallStack.length-i-1].oldLocales;
}
for (i = k; i < theStack.length; i++)
theStack [theStack.length -i-1] = new ToolsCallStackFrame (debugger, rStack [theStack.length -i-1]);
oldCallStack = theStack;
return theStack;
}
/**
* If this thread is suspended returns current local variables.
*
* @return current local variables.
*/
public AbstractVariable[] getLocales () {
if (debugger.synchronizer == null) return new AbstractVariable [0];
try {
return (AbstractVariable[]) new Protector ("ToolsThread.getLocales") { // NOI18N
public Object protect () throws Exception {
RemoteStackVariable[] v = thread.getStackVariables ();
HashMap newLocales = new HashMap ();
ToolsVariable[] rVariables = new ToolsVariable [v.length];
int i, k = v.length;
for (i = 0; i < k; i++) {
rVariables [i] = (ToolsVariable) oldLocales.get (v [i].getName ());
if (rVariables [i] == null)
rVariables [i] = new ToolsVariable (
debugger,
v [i].getName (),
v [i].getValue (),
v [i].getType ().toString ()
);
else {
rVariables [i].update (
v [i].getName (),
v [i].getValue (),
v [i].getType ().toString ()
);
rVariables [i].firePropertyChange ();
}
newLocales.put (v [i].getName (), rVariables [i]);
}
oldLocales = newLocales;
return rVariables;
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
return new ToolsVariable [0];
}
}
/**
* Returns name of file of this frame or null if thread has no frame.
*
* @return Returns name of file of this frame.
* @throws DebuggerException if informations about source are not included or some other error
* occurres.
*/
public String getSourceName () throws DebuggerException {
if (debugger.synchronizer == null) return ""; // NOI18N
try {
return (String) new Protector ("ToolsThread.getSourceName") { // NOI18N
public Object protect () throws Exception {
return thread.getCurrentFrame ().getRemoteClass ().getSourceFileName ();
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
} catch (Throwable e) {
if (e instanceof ThreadDeath) throw (ThreadDeath)e;
return ""; // NOI18N
}
}
// other methods ..............................................................
int getLastStackDepth () {
return lastStackDepth;
}
int getLastAction () {
return lastAction;
}
/** Sets last action performed on the thread and sets lastStackDepth value. */
void setLastAction (int action) {
lastAction = action;
try {
lastStackDepth = getStackDepth ();
}
catch (DebuggerException e) {
lastStackDepth = 10000; // troubles, what now ...
}
}
/**
* Returns RemoteThread for this thread.
*/
RemoteThread getRemoteThread () {
return thread;
}
/**
* Updates state of this thread.
*/
void threadChanged () {
// updateDebuggerState ();
SwingUtilities.invokeLater (new Runnable () {
public void run () {
firePropertyChange ();
}
});
}
/**
* Helper method.
*/
protected void firePropertyChange () {
super.firePropertyChange (null, null, null);
}
/**
* Equals if RemoteThreads equals.
*/
public boolean equals (Object o) {
if (!(o instanceof ToolsThread)) return false;
return thread.equals (((ToolsThread) o).thread);
}
/**
* Helper method.
*/
public int hashCode () {
return thread.hashCode ();
}
// unsafe methods ..............................................................
RemoteStackFrame getCurrentStackIn () throws Exception {
if (debugger.synchronizer == null) return null;
return (RemoteStackFrame) new Protector ("ToolsThread.getCurrentStackIn") { // NOI18N
public Object protect () throws Exception {
return thread.getCurrentFrame ();
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
}
boolean isSuspendedIn () {
if (debugger.synchronizer == null) return false;
return ((Boolean) new Protector ("ToolsThread.dumpStackIn") { // NOI18N
public Object protect () {
return new Boolean (thread.isSuspended ());
}
}.wait (debugger.synchronizer, debugger.killer)).booleanValue ();
}
RemoteStackFrame[] dumpStackIn () throws Exception {
if (debugger.synchronizer == null) return null;
return (RemoteStackFrame[]) new Protector ("ToolsThread.dumpStackIn") { // NOI18N
public Object protect () throws Exception {
return thread.dumpStack ();
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
}
void suspendIn () throws Exception {
if (debugger.synchronizer == null) return;
new Protector ("ToolsThread.suspendIn") { // NOI18N
public Object protect () throws Exception {
thread.suspend ();
return null;
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
}
void resumeIn () throws Exception {
if (debugger.synchronizer == null) return;
new Protector ("ToolsThread.resumeIn") { // NOI18N
public Object protect () throws Exception {
thread.resume ();
return null;
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
}
void contIn () throws Exception {
if (debugger.synchronizer == null) return;
new Protector ("ToolsThread.contIn") { // NOI18N
public Object protect () throws Exception {
thread.cont ();
return null;
}
}.throwAndWait (debugger.synchronizer, debugger.killer);
}
}
/*
* Log
* 15 Gandalf-post-FCS1.13.3.0 3/28/00 Daniel Prusa
* 14 Gandalf 1.13 1/13/00 Daniel Prusa NOI18N
* 13 Gandalf 1.12 1/10/00 Jan Jancura Refresh of locales
* updated
* 12 Gandalf 1.11 1/6/00 Jan Jancura Rename from Abstract
* 11 Gandalf 1.10 11/8/99 Jan Jancura Somma classes renamed
* 10 Gandalf 1.9 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 9 Gandalf 1.8 10/1/99 Jan Jancura Current thread & bug 4108
* 8 Gandalf 1.7 9/15/99 Jan Jancura
* 7 Gandalf 1.6 8/17/99 Jan Jancura Actions for session added
* & Thread group current property
* 6 Gandalf 1.5 7/24/99 Jan Jancura Bug in Suspend / resume
* thread in enterprise deb.
* 5 Gandalf 1.4 7/13/99 Jan Jancura
* 4 Gandalf 1.3 6/9/99 Jan Jancura
* 3 Gandalf 1.2 6/9/99 Ian Formanek ---- Package Change To
* org.openide ----
* 2 Gandalf 1.1 6/4/99 Jan Jancura
* 1 Gandalf 1.0 6/1/99 Jan Jancura
* $
*/